/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package interprete;

import interprete.PilaBanderas.estado;
import interprete.Token.token;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextArea;

/**
 *
 * @author lynx
 */
class Sintaxis{

    private Lexico lex;
    private TablaSimbolos tablaSímbolos;
    private boolean ejecutar;
    private PilaFunciones pilaFunciones;
    private PilaAritmeticaLogica pilaAritméticaLógica;
    private PilaBanderas pilaBanderas;
    private ArrayList arreglos;

    Sintaxis(String cadena, TablaSimbolos tablaSímbolos, boolean ejecutar) {
        lex = new Lexico(cadena);
        this.tablaSímbolos = tablaSímbolos;
        this.ejecutar = ejecutar;
        pilaFunciones = new PilaFunciones();
        if (ejecutar) {
            pilaAritméticaLógica = new PilaAritmeticaLogica();
            pilaBanderas = new PilaBanderas();
            arreglos = new ArrayList();
        }
    }

    private void mensaje(String mensaje) {
        Estado e = lex.get();
        System.out.println(e.línea + " -- " + mensaje);
    }

    private void salida(String mensaje) {
        System.out.println(mensaje);
    }

    boolean programa() {
        if (principal()) {
            if (funciones()) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    private boolean principal() {
        Token t = lex.siguiente();
        if (t.token == token.INICIO) {
            pilaFunciones.mete(t);
            if (ejecutar) {
                pilaBanderas.mete(estado.EJECUTAR);
            }
            if (cuerpo()) {
                t = lex.siguiente();
                if (t.token == token.FIN) {
                    pilaFunciones.saca();
                    if (ejecutar) {
                        pilaBanderas.saca();
                        ejecutar = false;
                    }
                    return true;
                } else {
                    mensaje("Error: Se esperaba sentencia fin");
                    return false;
                }
            } else {
                mensaje("Error: Se esperaban alginas instrucciones");
                return false;
            }
        } else {
            mensaje("Error: Se esperaba inicio");
            return false;
        }
    }

    private boolean funciones() {
        if (función(null)) {
            if (funciones()) {
                return true;
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

    private boolean función(ArrayList<Token> argumentos) {
        Estado e = lex.get();
        Token t = lex.siguiente();
        Token nombre = t;
        nombre.segmento(e.i);
        ArrayList<Token> parámetros = (argumentos != null ? new ArrayList<Token>() : null);
        if (t.token == token.VARIABLE) {
            t = lex.siguiente();
            if (t.token == token.PI) {
                nombre.tipo(Token.tipo.FUNCIÓN);
                pilaFunciones.mete(nombre);
                if (parámetros(parámetros)) {
                    if (argumentos != null) {
                        if (argumentos.size() == parámetros.size()) {
                            for (int i = 0; i < argumentos.size(); i++) {
                                Token p = parámetros.get(i);
                                Token q = argumentos.get(i);
                                if (q.tipo() != Token.tipo.ARREGLO) {
                                    p.valor(q.valor());
                                    tablaSímbolos.asigna(p);
                                } else {
                                    p.tipo(Token.tipo.ARREGLO);
                                    p.arreglo(q.arreglo());
                                }
                            }
                        } else {
                            mensaje("Cantidad de argumentos inválida");
                        }
                    }
                    t = lex.siguiente();
                    if (t.token == token.PD) {
                        if (!ejecutar) {
                            tablaSímbolos.agrega(nombre);
                        }
                        if (cuerpo()) {
                            t = lex.siguiente();
                            if (t.token == token.REGRESA) {
                                if (elemento(null)) {
                                    pilaFunciones.saca();
                                    return true;
                                } else {
                                    mensaje("Error, se esperaba un elemento");
                                    return false;
                                }
                            } else {
                                mensaje("Error: se esperaba regresa");
                                return false;
                            }
                        } else {
                            mensaje("Error: se esperaban algunas instrucciones");
                            return false;
                        }
                    } else {
                        mensaje("Error: se esperaba )");
                        return false;
                    }
                } else {
                    mensaje("Error: se esperaban algunos argumentos");
                    return false;
                }
            } else {
                mensaje("Error: se esperaba (");
                return false;
            }
        } else {
            return false;
        }
    }

    private boolean parámetros(ArrayList<Token> parámetros) {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.VARIABLE) {
            t.padre((Token) pilaFunciones.ver());
            t.tipo(Token.tipo.VARIABLE);
            tablaSímbolos.agrega(t);
            if (parámetros != null) {
                parámetros.add(t);
            }
            if (parámetros2(parámetros)) {
                return true;
            } else {
                return false;
            }
        } else {
            lex.unget(e);
            return true;
        }
    }

    private boolean parámetros2(ArrayList<Token> parámetros) {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.COMA) {
            t = lex.siguiente();
            if (t.token == token.VARIABLE) {
                t.padre((Token) pilaFunciones.ver());
                tablaSímbolos.agrega(t);
                if (parámetros != null) {
                    parámetros.add(t);
                }
                if (parámetros2(parámetros)) {
                    return true;
                } else {
                    return false;
                }
            } else {
                mensaje("Error: se esperaba un nombre");
                return false;
            }
        } else {
            lex.unget(e);
            return true;
        }
    }

    private boolean cuerpo() {
        Estado e = lex.get();
        if (instruccion()) {
            cuerpo();
            return true;
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean instruccion() {
        if (operacion()) {
            return true;
        }
        if (escribe()) {
            return true;
        }
        if (lee()) {
            return true;
        }
        if (si()) {
            return true;
        }
        if (mientras(false, null)) {
            return true;
        }
        if (has()) {
            return true;
        }
        if (llamada()) {
            return true;
        }
        if (define()) {
            return true;
        }
        return false;
    }

    private boolean define() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        Casilla casilla;
        if (t.token == token.DEFINE) {
            casilla = arreglo(true);
            if (casilla != null) {
                return true;
            } else {
                return false;
            }
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean operacion() {
        Estado e = lex.get();
        Token t;
        Casilla casilla = arreglo(false);
        if (casilla != null) {
            t = lex.siguiente();
            if (t.token == token.ASIGNACIÓN) {
                if (expreAritmética()) {
                    if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                        pilaAritméticaLógica.asignación();
                        casilla.valor(pilaAritméticaLógica.saca().valor());
                    }
                    return true;
                }
            } else {
                mensaje("Error: se eperaba asignación");
                return false;
            }
        }
        lex.unget(e);
        t = lex.siguiente();
        if (t.token == token.VARIABLE) {
            t.tipo(Token.tipo.VARIABLE);
            t.padre((Token) pilaFunciones.ver());
            t = tablaSímbolos.agrega(t);
            if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                pilaAritméticaLógica.mete(t);
            }
            t = lex.siguiente();
            if (t.token == token.ASIGNACIÓN) {
                if (expreAritmética()) {
                    if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                        pilaAritméticaLógica.asignación();
                        tablaSímbolos.asigna(pilaAritméticaLógica.saca());
                    }
                    return true;
                }
            } else {
                mensaje("Error: se eperaba asignación");
                return false;
            }
        }
        lex.unget(e);
        return false;
    }

    private boolean expreAritmética() {
        if (término()) {
            return expreAritmética2();
        } else {
            return false;
        }
    }

    private boolean expreAritmética2() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.MAS) {
            if (expreAritmética()) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    pilaAritméticaLógica.suma();
                }
                return true;
            } else {
                return false;
            }
        }
        if (t.token == token.MENOS) {
            if (expreAritmética()) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    pilaAritméticaLógica.resta();
                }
                return true;
            } else {
                return false;
            }
        }
        lex.unget(e);
        return true;
    }

    private boolean término() {
        if (factor()) {
            return término2();
        } else {
            return false;
        }
    }

    private boolean término2() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.POR) {
            if (término()) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    pilaAritméticaLógica.multiplicación();
                }
                return true;
            } else {
                return false;
            }
        }
        if (t.token == token.ENTRE) {
            if (término()) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    pilaAritméticaLógica.división();
                }
                return true;
            } else {
                return false;
            }
        }
        lex.unget(e);
        return true;
    }

    private boolean factor() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.PI) {
            if (expreAritmética()) {
                t = lex.siguiente();
                if (t.token == token.PD) {
                    return true;
                } else {
                    mensaje("Error: se esperaba )");
                    return false;
                }
            } else {
                mensaje("Error: se esperaba una expresión aritmética");
                return false;
            }
        } else {
            lex.unget(e);
        }
        t = lex.siguiente();
        if (t.token == token.MENOS) {
            if (factor()) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    pilaAritméticaLógica.menos();
                }
                return true;
            } else {
                mensaje("Error: se esperaba un factor");
                return false;
            }
        } else {
            lex.unget(e);
        }
        if (elemento(null)) {
            return true;
        } else {
            mensaje("Error: se esperaba un elemento");
            return false;
        }
    }

    private boolean escribe() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        ArrayList<Token> lista = null;
        if (t.token == token.ESCRIBE) {
            e = lex.get();
            if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                lista = new ArrayList<Token>();
            }
            if (lista(lista)) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    String cadena = "";
                    int i;
                    Token p;
                    for (i = 0; i < lista.size() - 1; i++) {
                        p = lista.get(i);
                        cadena += p.valor() + ", ";
                    }
                    p = lista.get(i);
                    cadena += p.valor();
                    salida(cadena);
                }
                return true;
            }
            lex.unget(e);
            t = lex.siguiente();
            if (t.token == token.CADENA) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    salida(t.lexema);
                }
                return true;
            }
            mensaje("Error: se esperaban algunos elementos para mostrar");
            return false;
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean lee() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        Casilla casilla = null;
        if (t.token == token.LEE) {
            /*casilla = arreglo(false);
            if (casilla != null) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    InputStreamReader isr = new InputStreamReader(System.in);
                    BufferedReader br = new BufferedReader(isr);
                    try {
                        System.out.print("Dame cadena: ");
                        String cadena = br.readLine();
                        try {
                            Double valor = Double.parseDouble(cadena);
                            casilla.valor(valor.doubleValue());
                            return true;
                        } catch (NumberFormatException ex) {
                            salida("Número en formato inválido");
                            return false;
                        }
                    } catch (IOException ex) {
                        salida("Error al leer desde el teclado");
                        return false;
                    }
                } else {
                    return true;
                }
            }*/
            t = lex.siguiente();
            if (t.token == token.VARIABLE) {
                t.tipo(Token.tipo.VARIABLE);
                t.padre(pilaFunciones.ver());
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    InputStreamReader isr = new InputStreamReader(System.in);
                    BufferedReader br = new BufferedReader (isr);
                    try {
                        Double valor = Double.parseDouble(br.readLine());
                        t.valor(valor);
                        tablaSímbolos.asigna(t);
                        return true;
                    } catch (IOException ex) {
                        salida(ex.getMessage());
                        return false;
                    } catch (NumberFormatException ex) {
                        salida("Número en formato inválido");
                        return false;
                    }
                } else {
                    return true;
                }
            } else {
                mensaje("Error: se esperaban algo que leer");
                return false;
            }
        } else {
            lex.unget(e);
            return false;
        }

    }

    private boolean lista(ArrayList<Token> lista) {
        Estado e = lex.get();
        if (elemento(lista)) {
            return lista2(lista);
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean lista2(ArrayList<Token> lista) {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.COMA) {
            return lista(lista);
        } else {
            lex.unget(e);
            return true;
        }
    }

    private boolean si() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.SI) {
            t = lex.siguiente();
            if (t.token == token.PI) {
                if (exprLógica()) {
                    t = lex.siguiente();
                    if (t.token == token.PD) {
                        if (ejecutar) {
                            switch (pilaBanderas.ver()) {
                                case EJECUTAR:
                                    Token resultado = pilaAritméticaLógica.saca();
                                    if (resultado.valor() == 1) {
                                        pilaBanderas.mete(estado.EJECUTAR);
                                    } else {
                                        pilaBanderas.mete(estado.NO_EJECUTAR);
                                    }
                                    break;
                                case NO_EJECUTAR:
                                case INDIFERENTE:
                                    pilaBanderas.mete(estado.INDIFERENTE);
                                    break;
                            }
                        }
                        if (cuerpo()) {
                            if (sino()) {
                                t = lex.siguiente();
                                if (t.token == token.FIN) {
                                    if (ejecutar) {
                                        pilaBanderas.saca();
                                    }
                                    return true;
                                } else {
                                    mensaje("Error, se esperaba fin");
                                    return false;
                                }
                            } else {
                                return false;
                            }
                        } else {
                            mensaje("Error: Se esperaban alginas instrucciones");
                            return false;
                        }
                    } else {
                        mensaje("Error, se esperaba )");
                        return false;
                    }
                } else {
                    mensaje("Error, se esperaba una expresión lógica");
                    return false;
                }
            } else {
                mensaje("Error, se esperaba (");
                return false;
            }
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean exprLógica() {
        if (relación()) {
            return exprLógica2();
        } else {
            return false;
        }
    }

    private boolean exprLógica2() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (operadorLógico(t)) {
            if (exprLógica()) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    switch (t.token) {
                        case Y:
                            pilaAritméticaLógica.y();
                            break;
                        case O:
                            pilaAritméticaLógica.y();
                            break;
                        case NO:
                            pilaAritméticaLógica.y();
                            break;
                    }
                }
                return true;
            } else {
                mensaje("Error, se esperaba una expresión lógica");
                return false;
            }
        } else {
            lex.unget(e);
            return true;
        }
    }

    private boolean operadorLógico(Token t) {
        if (t.token == token.Y || t.token == token.O || t.token == token.NO) {
            return true;
        }
        return false;
    }

    private boolean relación() {
        Estado e = lex.get();
        Token t;
        if (elemento(null)) {
            t = lex.siguiente();
            if (operadorRelacional(t)) {
                if (elemento(null)) {
                    if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                        switch (t.token) {
                            case MAYOR:
                                pilaAritméticaLógica.mayor();
                                break;
                            case MAYOR_IGUAL:
                                pilaAritméticaLógica.mayorIgual();
                                break;
                            case MENOR:
                                pilaAritméticaLógica.menor();
                                break;
                            case MENOR_IGUAL:
                                pilaAritméticaLógica.menorIgual();
                                break;
                            case DIFERENTE:
                                pilaAritméticaLógica.diferente();
                                break;
                            case IGUALDAD:
                                pilaAritméticaLógica.igual();
                                break;
                        }
                    }
                    return true;
                } else {
                    mensaje("Error: se esperaba un elemento");
                    return false;
                }
            } else {
                mensaje("Error: se esperaba un operador relacional");
                return false;
            }
        } else {
            lex.unget(e);
            t = lex.siguiente();
            if (t.token == token.PI) {
                if (exprLógica()) {
                    t = lex.siguiente();
                    if (t.token == token.PD) {
                        return true;
                    } else {
                        mensaje("Error: se esperaba )");
                        return false;
                    }
                } else {
                    mensaje("Error: se esperaba una expresión lógica");
                    return false;
                }
            } else {
                if (t.token == token.NO) {
                    if (exprLógica()) {
                        if (ejecutar) {
                            pilaAritméticaLógica.no();
                        }
                        return true;
                    } else {
                        mensaje("Error: se esperaba una expresión lógica");
                        return false;
                    }
                } else {
                    mensaje("Error: se esperaba un elemento, ( o no");
                    return false;
                }
            }
        }
    }

    private boolean operadorRelacional(Token t) {
        if (t.token == token.MENOR || t.token == token.MENOR_IGUAL || t.token == token.MAYOR || t.token == token.MAYOR_IGUAL || t.token == token.IGUALDAD || t.token == token.DIFERENTE) {
            return true;
        } else {
            return false;
        }
    }

    private boolean sino() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.SINO) {
            if (ejecutar) {
                switch (pilaBanderas.saca()) {
                    case EJECUTAR:
                        pilaBanderas.mete(estado.NO_EJECUTAR);
                        break;
                    case NO_EJECUTAR:
                        pilaBanderas.mete(estado.EJECUTAR);
                        break;
                }
            }
            if (cuerpo()) {
                return true;
            } else {
                mensaje("Error: Se esperaban alginas instrucciones");
                return false;
            }
        } else {
            lex.unget(e);
            return true;
        }
    }

    private boolean mientras(boolean has, Estado e2) {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.MIENTRAS) {
            t = lex.siguiente();
            if (t.token == token.PI) {
                if (exprLógica()) {
                    t = lex.siguiente();
                    if (t.token == token.PD) {
                        if (!has) {
                            if (ejecutar) {
                                switch (pilaBanderas.ver()) {
                                    case EJECUTAR:
                                        Token resultado = pilaAritméticaLógica.saca();
                                        if (resultado.valor() == 1) {
                                            pilaBanderas.mete(estado.EJECUTAR);
                                        } else {
                                            pilaBanderas.mete(estado.NO_EJECUTAR);
                                        }
                                        break;
                                    case NO_EJECUTAR:
                                    case INDIFERENTE:
                                        pilaBanderas.mete(estado.INDIFERENTE);
                                        break;
                                }
                            }
                            if (cuerpo()) {
                                t = lex.siguiente();
                                if (t.token == token.FIN) {
                                    if (ejecutar) {
                                        estado estado = pilaBanderas.saca();
                                        if (estado == estado.EJECUTAR) {
                                            lex.unget(e);
                                        }
                                    }
                                    return true;
                                } else {
                                    mensaje("Error, se esperaba fin");
                                    return false;
                                }
                            } else {
                                return false;
                            }
                        } else {
                            t = lex.siguiente();
                            if (t.token == token.FIN) {
                                if (ejecutar) {
                                    estado estado = pilaBanderas.saca();
                                    if (estado == estado.EJECUTAR) {
                                        Token resultado = pilaAritméticaLógica.saca();
                                        if (resultado.valor() == 1) {
                                            pilaBanderas.mete(estado.EJECUTAR);
                                            lex.unget(e2);
                                        }
                                    }
                                }
                                return true;
                            } else {
                                mensaje("Error, se esperaba fin");
                                return false;
                            }
                        }
                    } else {
                        mensaje("Error, se esperaba )");
                        return false;
                    }
                } else {
                    mensaje("Error, se esperaba una expresión lógica");
                    return false;
                }
            } else {
                mensaje("Error, se esperaba (");
                return false;
            }
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean has() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        if (t.token == token.HAS) {
            if (ejecutar) {
                switch (pilaBanderas.ver()) {
                    case EJECUTAR:
                        pilaBanderas.mete(estado.EJECUTAR);
                        break;
                    case NO_EJECUTAR:
                    case INDIFERENTE:
                        pilaBanderas.mete(estado.INDIFERENTE);
                        break;
                }
            }
            if (cuerpo()) {
                return mientras(true, e);
            } else {
                mensaje("Error: Se esperaban alginas instrucciones");
                return false;
            }
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean llamada() {
        Estado e = lex.get();
        Token t = lex.siguiente();
        Token nombre;
        Token nombre2;
        ArrayList<Token> argumentos = null;
        ArrayList<Token> lista = null;
        if (t.token == token.VARIABLE) {
            nombre = t;
            nombre.tipo(Token.tipo.FUNCIÓN);
            nombre2 = new Token(token.VARIABLE, nombre.lexema, 0);
            t = lex.siguiente();
            if (t.token == token.PI) {
                if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                    lista = new ArrayList<Token>();
                }
                if (lista(lista)) {
                    if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                        argumentos = new ArrayList();
                        for (Token p : lista) {
                            argumentos.add(p);
                        }
                    }
                }
                t = lex.siguiente();
                if (t.token == token.PD) {
                    if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                        e = lex.get();//continuar desde aquí después de hacer la llamada
                        nombre = tablaSímbolos.buscarFuncion(nombre);
                        if (nombre != null) {
                            lex.unget(new Estado(nombre.segmento(), e.línea));
                            función(argumentos);
                            lex.unget(e);
                        } else {
                            if (nombre2.lexema.compareTo("e") == 0) {
                                if (lista.size() == 0) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.E));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("pi") == 0) {
                                if (lista.size() == 0) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.PI));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("abs") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.abs(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("acos") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.acos(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("asen") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.asin(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("atan") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.atan(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("techo") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.ceil(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("techo") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.ceil(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("cos") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.cos(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("exp") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.exp(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("piso") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.floor(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("residuo") == 0) {
                                if (lista.size() == 2) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.IEEEremainder(lista.get(0).valor(), lista.get(1).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("log") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.log(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("mayor") == 0) {
                                if (lista.size() == 2) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.max(lista.get(0).valor(), lista.get(1).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("menor") == 0) {
                                if (lista.size() == 2) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.min(lista.get(0).valor(), lista.get(1).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("potencia") == 0) {
                                if (lista.size() == 2) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.pow(lista.get(0).valor(), lista.get(1).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("aleatorio") == 0) {
                                if (lista.size() == 0) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.random()));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("redondea") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.rint(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("seno") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.sin(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("raiz") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.sqrt(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("tan") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.tan(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("radianes") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.toRadians(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            if (nombre2.lexema.compareTo("grados") == 0) {
                                if (lista.size() == 1) {
                                    pilaAritméticaLógica.mete(new Token(token.LITERAL, "", Math.toDegrees(lista.get(0).valor())));
                                    return true;
                                } else {
                                    mensaje("Error, cantidad de argumentos inválida");
                                    return false;
                                }
                            }
                            mensaje("Error, función desconocida");
                            return false;
                        }
                    }
                    return true;
                } else {
                    mensaje("Error: se esperaba )");
                    return false;
                }
            } else {
                lex.unget(e);
                return false;
            }
        } else {
            lex.unget(e);
            return false;
        }
    }

    private Casilla arreglo(boolean define) {
        Estado e;
        Token t;
        ArrayList<Integer> dimensiones = (ejecutar && pilaBanderas.ver() == estado.EJECUTAR ? new ArrayList<Integer>() : null);
        ArrayList<Token> lista = (ejecutar && pilaBanderas.ver() == estado.EJECUTAR ? new ArrayList<Token>() : null);
        Arreglo arreglo;
        e = lex.get();
        t = lex.siguiente();
        if (t.token == token.VARIABLE) {
            if (dimensiones(dimensiones, lista)) {
                t.tipo(Token.tipo.ARREGLO);
                t.padre(pilaFunciones.ver());
                if (ejecutar) {
                    int[] dimensiones2 = new int[dimensiones.size()];
                    for (int i = 0; i < dimensiones.size(); i++) {
                        dimensiones2[i] = dimensiones.get(i);
                    }
                    if (define) {
                        arreglo = new Arreglo(dimensiones2);
                        t = tablaSímbolos.agrega(t);
                        t.arreglo(arreglo);
                        arreglos.add(arreglo);
                        return new Casilla(0);
                    } else {
                        t = tablaSímbolos.buscarFuncion(t);
                        arreglo = t.arreglo();
                        try {
                            return arreglo.obtenValor(dimensiones2);
                        } catch (Exception ex) {
                            mensaje(ex.getMessage());
                            return null;
                        }
                    }
                } else {
                    return new Casilla(0);
                }
            } else {
                lex.unget(e);
                return null;
            }
        } else {
            lex.unget(e);
            return null;
        }
    }

    private boolean dimensiones(ArrayList<Integer> dimensiones, ArrayList<Token> lista) {
        Estado e = lex.get();
        int i = 0;
        if (dimensión(dimensiones, lista)) {
            return dimensiones2(dimensiones, lista);
        } else {
            lex.unget(e);
            return false;
        }
    }

    private boolean dimensión(ArrayList<Integer> dimensiones, ArrayList<Token> lista) {
        Token t = lex.siguiente();
        if (t.token == token.CI) {
            if (elemento(lista)) {
                if (dimensiones != null) {
                    Token elemento = pilaAritméticaLógica.saca();
                    dimensiones.add((int) elemento.valor());
                }
                t = lex.siguiente();
                if (t.token == token.CD) {
                    return true;
                } else {
                    mensaje("Se esperaba un corchete");
                    return false;
                }
            } else {
                mensaje("Se esperaba un elemento");
                return false;
            }
        } else {
            return false;
        }
    }

    private boolean dimensiones2(ArrayList<Integer> dimensiones, ArrayList<Token> lista) {
        Estado e = lex.get();
        if (dimensión(dimensiones, lista)) {
            return dimensiones2(dimensiones, lista);
        } else {
            lex.unget(e);
            return true;
        }
    }

    private boolean elemento(ArrayList<Token> lista) {
        Estado e = lex.get();
        Token t;
        Casilla casilla = arreglo(false);
        if (casilla != null) {
            if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                pilaAritméticaLógica.mete(new Token(token.LITERAL, "", casilla.valor()));
            }
            return true;
        }
        lex.unget(e);
        if (llamada()) {
            if (lista != null) {
                lista.add(pilaAritméticaLógica.saca());
            }
            return true;
        }
        lex.unget(e);
        t = lex.siguiente();
        if (t.token == token.VARIABLE) {
            t.tipo(Token.tipo.VARIABLE);
            t.padre((Token) pilaFunciones.ver());
            tablaSímbolos.agrega(t);
            if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                if (lista == null) {
                    pilaAritméticaLógica.mete(t);
                } else {
                    lista.add(t);
                }

            }
            return true;
        }
        if (t.token == token.LITERAL) {
            t.tipo(Token.tipo.LITERAL);
            if (ejecutar && pilaBanderas.ver() == estado.EJECUTAR) {
                if (lista == null) {
                    pilaAritméticaLógica.mete(t);
                } else {
                    lista.add(t);
                }
            }
            return true;
        } else {
            lex.unget(e);
            return false;
        }
    }
}
